package main

import "fmt"

/*
  享元模式
  使用共享物件，来尽可能多地减少内存使用量以及共享给尽可能多的相似组件。
  它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。
  通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构，当需要使用时再将它们传递给享元。
  例子:
  游戏中的角色都有基础属性
  游戏中的角色都会穿上装备
  装备是不同的单基础属性都是一样的
  结合装饰者模式来开发一个角色穿上不同装备后，HP上限和MP上限增加的例子
*/

//属性接口
type Property interface {
	GetHpLimit() int
	GetMpLimit() int
}
//裸装
type PersonBase struct {
     maxHp int
     maxMp int
}

func NewPersonBase() *PersonBase {
	return &PersonBase{100,100}
}

func (p *PersonBase) GetHpLimit()  int{
	return p.maxHp
}

func (p *PersonBase) GetMpLimit()  int{
    return p.maxMp
}

//带头盔
type Helmet struct {
	base Property
	hpAdd int
	mpAdd int
}

func (h *Helmet) GetHpLimit()  int{
	return h.base.GetHpLimit() + h.hpAdd
}

func (h *Helmet) GetMpLimit()  int{
	return h.base.GetMpLimit() + h.mpAdd
}

func NewHelmet(property Property,hpAdd,mpAdd int)*Helmet{
	return &Helmet{property,hpAdd,mpAdd}
}

//一个享元工厂来存放享元
type Element struct {
  value interface{}
}

type FlyweightFactory struct {
	pool map[string]*Element
}

func (f *FlyweightFactory) GetElement(key string) interface{} {
	return f.pool[key].value
}
func (f *FlyweightFactory) SetElement(key string, value interface{})  {
	f.pool[key] = &Element{value}
}

func NewFlyweight() *FlyweightFactory  {
	fly := FlyweightFactory{}
	fly.pool = make(map[string]*Element)
	return &fly
}

func main() {
	//	创建享元
	fly := NewFlyweight()
	base := NewPersonBase()
	fly.SetElement("PersonBase",base)

	//	生成两个人物
	people1 := fly.GetElement("PersonBase").(Property)
	people2 := fly.GetElement("PersonBase").(Property)

	//	捡到装备了——装饰者
	people1 = NewHelmet(people1,10,10)
	people1 = NewHelmet(people1,100,100)

	//	获取它们血量上限和魔法上限
	hp1 := people1.GetHpLimit()
	mp1 := people1.GetMpLimit()

	hp2 := people2.GetHpLimit()
	mp2 := people2.GetMpLimit()

	fmt.Printf("People1:\nHP:%d\nMP:%d\n",hp1,mp1)
	fmt.Printf("People2:\nHP:%d\nMP:%d\n",hp2,mp2)
}
